package org.example.wx.Node;


import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.example.wx.Node.Interface.ServiceRegister;

import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

public class ZooKeeperServer implements ServiceRegister {

    //应用程序的端口，不是zookeeper的客户端的端口
    private Integer port;

    private static final Integer lastVersion = -1;

    private ZooKeeper zookeeper;

    private String connectString = "192.168.186.100：2181";

    private final CountDownLatch countDownLatch = new CountDownLatch(1);

    public ZooKeeperServer(Integer port) {
        this.port = port;
        try {
            //zookeeper的链接地址从配置文件当中获取
            zookeeper = new ZooKeeper(connectString, 40000, new Watcher() {
                @Override
                public void process(WatchedEvent watchedEvent) {
                    if (Event.KeeperState.SyncConnected == watchedEvent.getState()) {
                        //如果收到了服务端的响应事件，连接成功
                        System.out.println("成功连接zookeeper服务器");
                        countDownLatch.countDown();
                    }
                }
            });
            countDownLatch.await();
        } catch (IOException | InterruptedException ioException) {
            System.out.println("zookeeper connect failed!");
            ioException.printStackTrace();
        }
    }

    /**
     * 将当前服务器的地址写入到zookeeper中名称为serviceName的节点
     *
     * @param serviceName
     */
    @Override
    public void registService(String serviceName) throws Exception {
        String path = getPath(serviceName);
        Stat existsStat = zookeeper.exists(path, false);
        //如果节点不存在，则创建节点
        if (null == existsStat) {
            zookeeper.create(path, "".getBytes(StandardCharsets.UTF_8), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }
        //获取当前服务器的ip地址并且写入节点当中
        String ipAddress = getServerIpAddressAndPort();
        String data = new String(zookeeper.getData(path, false, null));
        String newData = data + ";" + ipAddress;
        zookeeper.setData(path, newData.getBytes(StandardCharsets.UTF_8), lastVersion);
    }

    /**
     * 将当前服务器地址从zookeeper中名称为serviceName的节点里删除
     *
     * @param serviceName
     * @throws Exception
     */
    @Override
    public void deRegistService(String serviceName) throws Exception {
        String path = getPath(serviceName);
        Stat existsStat = zookeeper.exists(path, false);
        if (null == existsStat) {
            System.out.println("zookeeper节点： " + path + "未找到");
            return;
        }
        final String ipAddress = getServerIpAddressAndPort();
        String data = new String(zookeeper.getData(path, false, null));
        System.out.println("zookeeper节点： " + path + "的数据： " + data);

        if (data.contains(ipAddress)) {
            String newData = Arrays.stream(data.split(";")).filter(ipAddress::equals).collect(Collectors.joining(":"));
            zookeeper.setData(path, newData.getBytes(StandardCharsets.UTF_8), lastVersion);
            System.out.println("修改后zookeeper节点： " + path + "的数据： " + data);
        }
    }

    /**
     * 获取zookeeper对应服务的所有数据，只获取服务的地址，不创建链接
     *
     * @param serviceName
     * @return
     * @throws KeeperException
     * @throws InterruptedException
     */
    @Override
    public List<String> refreshServiceInfos(String serviceName) throws KeeperException, InterruptedException {
        String path = getPath(serviceName);
        Stat existsStat = zookeeper.exists(path, false);
        //如果没有对应的服务节点，则直接返回null，不创建服务节点
        if (null == existsStat) {
            return new ArrayList<>();
        } else {
            String data = new String(zookeeper.getData(path, false, null));
            if ("".equals(data)) {
                return new ArrayList<>();
            } else {
                return Arrays.asList(data.split(";"));
            }
        }
    }

    /**
     * 获取服务需要注册的路径
     *
     * @param serviceName
     * @return
     */
    private String getPath(String serviceName) {
        return "/" + serviceName;
    }

    /**
     * 获取当前服务器的ip地址
     *
     * @return
     * @throws UnknownHostException
     */
    private String getServerIpAddressAndPort() throws UnknownHostException {
        InetAddress address = InetAddress.getLocalHost();
        return address.getHostAddress() + ":" + port;
    }


}
